package com.wsjzzcbq.qianyuan.common.aspect;

import com.wsjzzcbq.qianyuan.common.annotation.Logical;
import com.wsjzzcbq.qianyuan.common.annotation.RequiresPermissions;
import com.wsjzzcbq.qianyuan.common.cache.CacheService;
import com.wsjzzcbq.qianyuan.common.constant.CacheConsts;
import com.wsjzzcbq.qianyuan.common.constant.SysConsts;
import com.wsjzzcbq.qianyuan.common.exception.NoHasPermissionExpection;
import com.wsjzzcbq.qianyuan.common.util.CookieUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;

/**
 * PermissionsAspect
 *
 * @author wsjz
 * @date 2022/07/26
 */
@Slf4j
@Aspect
@Component
public class PermissionsAspect {

    @Autowired
    private CacheService cacheService;

    @Pointcut("@annotation(com.wsjzzcbq.qianyuan.common.annotation.RequiresPermissions)")
    public void annotationAspect() {
    }

    @Around("annotationAspect()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //获取权限注解
        RequiresPermissions annotation = getAnnotation(point);
        Logical logical = annotation.logical();
        String[] values = annotation.value();

        //获取用户权限
        String token = CookieUtils.getValyeByName(SysConsts.COOKIE_TOKEN);
        Set<String> permissions = cacheService.getSet(CacheConsts.permissionKey(token));

        if (Logical.AND.equals(logical)) {
            for (String v : values) {
                if (!permissions.contains(v)) {
                    throw new NoHasPermissionExpection("User is not permitted [" + v + "]");
                }
            }
        }

        if (Logical.OR.equals(logical) && values.length > 0) {
            boolean hasPermission = false;
            for (String v : values) {
                if (permissions.contains(v)) {
                    hasPermission = true;
                    break;
                }
            }
            if (!hasPermission) {
                throw new NoHasPermissionExpection("User is not permitted " + Arrays.toString(values));
            }
        }

        return point.proceed();
    }

    /**
     * 获取切点上的 RequiresPermissions 注解
     * @param point
     * @return
     */
    private RequiresPermissions getAnnotation(ProceedingJoinPoint point) throws NoSuchMethodException {
        Object[] args = point.getArgs();
        Class<?>[] argTypes = new Class[point.getArgs().length];
        for (int i = 0; i < args.length; i++) {
            argTypes[i] = args[i].getClass();
        }

        Method method = point.getTarget().getClass().getMethod(point.getSignature().getName(), argTypes);

        return method.getAnnotation(RequiresPermissions.class);
    }

}
